package network.action;

import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JColorChooser;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;

import network.editor.BasicNetworkEditor;
import network.editor.EditorResource;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;

import com.mxgraph.analysis.mxDistanceCostFunction;
import com.mxgraph.analysis.mxGraphAnalysis;
import com.mxgraph.io.mxCodec;
import com.mxgraph.io.mxVdxCodec;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGraphModel;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.handler.mxConnectionHandler;
import com.mxgraph.swing.util.mxGraphActions;
import com.mxgraph.swing.view.mxCellEditor;
import com.mxgraph.util.mxCellRenderer;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxResources;
import com.mxgraph.util.mxUtils;
import com.mxgraph.util.png.mxPngDecodeParam;
import com.mxgraph.util.png.mxPngEncodeParam;
import com.mxgraph.util.png.mxPngImageDecoder;
import com.mxgraph.util.png.mxPngImageEncoder;
import com.mxgraph.view.mxGraph;

/**
 * 所有的事件处理
 * @author zhangzuoqiang
 * <br/>Date: Aug 25, 2011
 */
public class EditorActions {
	
	private static Logger log = Logger.getLogger(EditorActions.class);

	/**
	 * 从事件源获得BasicNetworkEditor对象
	 * @param e
	 * @return
	 */
	public static final BasicNetworkEditor getEditor(ActionEvent e) {
		if (e.getSource() instanceof Component) {
			Component component = (Component) e.getSource();

			while (component != null
					&& !(component instanceof BasicNetworkEditor)) {
				component = component.getParent();
			}

			return (BasicNetworkEditor) component;
		}
		return null;
	}

	/**
	 * 是否显示画尺
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ToggleRulersItem extends JCheckBoxMenuItem {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public ToggleRulersItem(final BasicNetworkEditor editor, String name) {
			super(name);
			setSelected(editor.getGraphComponent().getColumnHeader() != null);
			addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					mxGraphComponent graphComponent = editor
							.getGraphComponent();
					if (graphComponent.getColumnHeader() != null) {
						graphComponent.setColumnHeader(null);
						graphComponent.setRowHeader(null);
					} else {
						graphComponent.setColumnHeaderView(new EditorRuler(
								graphComponent,
								EditorRuler.ORIENTATION_HORIZONTAL));
						graphComponent.setRowHeaderView(new EditorRuler(
								graphComponent,
								EditorRuler.ORIENTATION_VERTICAL));
					}
				}
			});
		}
	}

	/**
	 * 画布网格是否可见
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ToggleGridItem extends JCheckBoxMenuItem {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * 网格画布
		 * @param editor
		 * @param name
		 */
		public ToggleGridItem(final BasicNetworkEditor editor, String name) {
			super(name);
			setSelected(true);
			addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					mxGraphComponent graphComponent = editor
							.getGraphComponent();
					mxGraph graph = graphComponent.getGraph();
					boolean enabled = !graph.isGridEnabled();

					graph.setGridEnabled(enabled);
					graphComponent.setGridVisible(enabled);
					graphComponent.repaint();
					setSelected(enabled);
				}
			});
		}
	}

	/**
	 * 画布网格样式
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class GridStyleAction extends AbstractAction {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected int style;

		public GridStyleAction(int style) {
			this.style = style;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				graphComponent.setGridStyle(style);
				graphComponent.repaint();
			}
		}
	}

	/**
	 * 画布网格颜色
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class GridColorAction extends AbstractAction {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				Color newColor = JColorChooser.showDialog(graphComponent,
						mxResources.get("gridColor"),
						graphComponent.getGridColor());

				if (newColor != null) {
					graphComponent.setGridColor(newColor);
					graphComponent.repaint();
				}
			}
		}
	}

	/**
	 * 退出系统
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ExitAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			BasicNetworkEditor editor = getEditor(e);

			if (editor != null) {
				editor.exit();
			}
		}

	}

	/**
	 * 更换style
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class StylesheetAction extends AbstractAction {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected String stylesheet;

		public StylesheetAction(String stylesheet) {
			this.stylesheet = stylesheet;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				mxGraph graph = graphComponent.getGraph();
				mxCodec codec = new mxCodec();
				Document doc = EditorResource.getDocument(stylesheet);
				if (doc != null) {
					codec.decode(doc.getDocumentElement(),
							graph.getStylesheet());
					graph.refresh();
				}
			}
		}
	}

	/**
	 * undo和redo操作管理，true是undo，false是redo
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class HistoryAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		protected boolean undo;

		public HistoryAction(boolean undo) {
			this.undo = undo;
		}

		public void actionPerformed(ActionEvent e) {
			BasicNetworkEditor editor = getEditor(e);

			if (editor != null) {
				if (undo) {
					editor.getUndoManager().undo();
				} else {
					editor.getUndoManager().redo();
				}
			}
		}
	}

	/**
	 * 缩放策略
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ZoomPolicyAction extends AbstractAction {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected int zoomPolicy;

		public ZoomPolicyAction(int zoomPolicy) {
			this.zoomPolicy = zoomPolicy;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				graphComponent.setPageVisible(true);
				graphComponent.setZoomPolicy(zoomPolicy);
			}
		}
	}

	/**
	 * 画布比例
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ScaleAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		protected double scale;

		public ScaleAction(double scale) {
			this.scale = scale;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				double scale = this.scale;

				if (scale == 0) {
					String value = (String) JOptionPane.showInputDialog(
							graphComponent, "数值", "比例" + " (%)",
							JOptionPane.PLAIN_MESSAGE, null, null, "");

					if (value != null) {
						scale = Double.parseDouble(value.replace("%", "")) / 100;
					}
				}

				if (scale > 0) {
					graphComponent.zoomTo(scale, graphComponent.isCenterZoom());
				}
			}
		}

	}

	/**
	 * 页面设置，横向还是纵向
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class PageSetupAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				PrinterJob pj = PrinterJob.getPrinterJob();
				PageFormat format = pj.pageDialog(graphComponent
						.getPageFormat());
				if (format != null) {
					graphComponent.setPageFormat(format);
					graphComponent.zoomAndCenter();
				}
			}
		}

	}

	/**
	 * 新建画布
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class NewAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			BasicNetworkEditor editor = getEditor(e);

			if (editor != null) {
				if (!editor.isModified()
						|| JOptionPane.showConfirmDialog(editor, "放弃现有的修改吗?") == JOptionPane.YES_OPTION) {
					mxGraph graph = editor.getGraphComponent().getGraph();
					mxCell root = new mxCell();
					root.insert(new mxCell());
					graph.getModel().setRoot(root);
					editor.setModified(false);
					editor.setCurrentFile(null);
					editor.getGraphComponent().zoomAndCenter();
				}
			}
		}
	}

	/**
	 * 打开画布
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class OpenAction extends AbstractAction {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		protected String lastDir;

		protected void resetEditor(BasicNetworkEditor editor) {
			editor.setModified(false);
			editor.getUndoManager().clear();
			editor.getGraphComponent().zoomAndCenter();
		}

		/**
		 * Reads XML+PNG format.
		 */
		protected void openXmlPng(BasicNetworkEditor editor, File file)
				throws IOException {
			mxPngDecodeParam decodeParam = new mxPngDecodeParam();
			decodeParam.setGenerateEncodeParam(true);
			mxPngImageDecoder decoder = new mxPngImageDecoder(
					new FileInputStream(file), decodeParam);
			decoder.decodeAsRenderedImage();

			String[] text = decodeParam.getEncodeParam().getCompressedText();

			if (text != null) {
				for (int i = 0; i < text.length; i++) {
					// Finds the graph model entry in the compressed text chunks
					if (text[i].equals("mxGraphModel") && text.length > i) {
						Document document = mxUtils.parseXml(URLDecoder.decode(
								text[i + 1], "UTF-8"));
						mxCodec codec = new mxCodec(document);
						codec.decode(document.getDocumentElement(), editor
								.getGraphComponent().getGraph().getModel());
						editor.setCurrentFile(file);
						resetEditor(editor);

						return;
					}
				}
			}

			JOptionPane.showMessageDialog(editor,
					mxResources.get("imageContainsNoDiagramData"));
		}

		protected void openVdx(BasicNetworkEditor editor, File file,
				Document document) {
			mxGraph graph = editor.getGraphComponent().getGraph();

			// Replaces file extension with .mxe
			String filename = file.getName();
			filename = filename.substring(0, filename.length() - 4) + ".mxe";

			if (new File(filename).exists()
					&& JOptionPane.showConfirmDialog(editor, "要覆盖已有的文件吗?") != JOptionPane.YES_OPTION) {
				return;
			}

			((mxGraphModel) graph.getModel()).clear();
			mxVdxCodec.decode(document, graph);
			editor.setCurrentFile(new File(lastDir + "/" + filename));
		}
		
		public void actionPerformed(ActionEvent e) {
			BasicNetworkEditor editor = getEditor(e);

			if (editor != null) {
				if (!editor.isModified()
						|| JOptionPane.showConfirmDialog(editor, "要放弃已有的修改吗?") == JOptionPane.YES_OPTION) {
					mxGraph graph = editor.getGraphComponent().getGraph();

					if (graph != null) {
						String wd = (lastDir != null) ? lastDir : System
								.getProperty("user.dir");

						JFileChooser fc = new JFileChooser(wd);

//						 Adds file filter for supported file format
//						 DefaultFileFilter defaultFilter = new
//						 DefaultFileFilter(".mxe",
//						 "所有支持的格式 (.mxe, .png, .vdx)")
//						 {
//						
//						 public boolean accept(File file)
//						 {
//						 String lcase = file.getName().toLowerCase();
//						
//						 return super.accept(file)
//						 || lcase.endsWith(".png")
//						 || lcase.endsWith(".vdx");
//						 }
//						 };
//						 fc.addChoosableFileFilter(defaultFilter);
						DefaultFileFilter defaultFileFilter = new DefaultFileFilter(
								".png", "PNG+XML  " + "文件" + " (.png)");
						fc.addChoosableFileFilter(defaultFileFilter);
						fc.addChoosableFileFilter(new DefaultFileFilter(".vdx",
								"XML Drawing  " + "文件" + " (.vdx)"));
						fc.setFileFilter(defaultFileFilter);

						int rc = fc.showDialog(null,
								mxResources.get("openFile"));

						if (rc == JFileChooser.APPROVE_OPTION) {
							lastDir = fc.getSelectedFile().getParent();

							try {
								if (fc.getSelectedFile().getAbsolutePath()
										.toLowerCase().endsWith(".png")) {
									openXmlPng(editor, fc.getSelectedFile());
								} else {
									Document document = mxUtils
											.parseXml(mxUtils.readFile(fc
													.getSelectedFile()
													.getAbsolutePath()));

									if (fc.getSelectedFile().getAbsolutePath()
											.toLowerCase().endsWith(".vdx")) {
										openVdx(editor, fc.getSelectedFile(),
												document);
									} else {
										mxCodec codec = new mxCodec(document);
										codec.decode(
												document.getDocumentElement(),
												graph.getModel());
										editor.setCurrentFile(fc
												.getSelectedFile());
									}

									resetEditor(editor);
								}
							} catch (Exception ex) {
								JOptionPane.showMessageDialog(
										editor.getGraphComponent(),
										ex.toString(), "错误",
										JOptionPane.ERROR_MESSAGE);
							}
						}
					}
				}
			}
		}
	}

	/**
	 * 打印
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class PrintAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				PrinterJob pj = PrinterJob.getPrinterJob();

				if (pj.printDialog()) {
					PageFormat pf = graphComponent.getPageFormat();
					Paper paper = new Paper();
					double margin = 36;
					paper.setImageableArea(margin, margin, paper.getWidth()
							- margin * 2, paper.getHeight() - margin * 2);
					pf.setPaper(paper);
					pj.setPrintable(graphComponent, pf);

					try {
						pj.print();
					} catch (PrinterException ex) {
						log.error("打印出错:" + ex.getMessage());
					}
				}
			}
		}

	}

	/**
	 * 保存
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class SaveAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		protected boolean showDialog;
		protected String lastDir = null;

		public SaveAction(boolean showDialog) {
			this.showDialog = showDialog;
		}

		// 保存成xml＋png格式
		protected void saveXmlPng(BasicNetworkEditor editor, String filename,
				Color bg) throws IOException {
			mxGraphComponent graphComponent = editor.getGraphComponent();
			mxGraph graph = graphComponent.getGraph();

			// 创建一个PNG文件
			BufferedImage image = mxCellRenderer.createBufferedImage(graph,
					null, 1, bg, graphComponent.isAntiAlias(), null,
					graphComponent.getCanvas());

			// 创建xml
			mxCodec codec = new mxCodec();
			String xml = URLEncoder.encode(
					mxUtils.getXml(codec.encode(graph.getModel())), "UTF-8");

			mxPngEncodeParam param = mxPngEncodeParam
					.getDefaultEncodeParam(image);
			param.setCompressedText(new String[] { "mxGraphModel", xml });

			// 保存成png
			FileOutputStream outputStream = new FileOutputStream(new File(
					filename));
			try {
				mxPngImageEncoder encoder = new mxPngImageEncoder(outputStream,
						param);
				if (image != null) {
					encoder.encode(image);
					editor.setModified(false);
					editor.setCurrentFile(new File(filename));
				} else {
					JOptionPane.showMessageDialog(graphComponent, "没有图像数据");
				}
			} finally {
				outputStream.close();
			}
		}

		public void actionPerformed(ActionEvent e) {
			BasicNetworkEditor editor = getEditor(e);

			if (editor != null) {
				mxGraphComponent graphComponent = editor.getGraphComponent();
				mxGraph graph = graphComponent.getGraph();
				FileFilter selectedFilter = null;
				DefaultFileFilter xmlPngFilter = new DefaultFileFilter(".png",
						"PNG+XML 文件 (.png)");
				String filename = null;
				boolean dialogShown = false;
				if (showDialog || editor.getCurrentFile() == null) {
					String wd;

					if (lastDir != null) {
						wd = lastDir;
					} else if (editor.getCurrentFile() != null) {
						wd = editor.getCurrentFile().getParent();
					} else {
						wd = System.getProperty("user.dir");
					}

					JFileChooser fc = new JFileChooser(wd);

					FileFilter defaultFilter = xmlPngFilter;
					fc.addChoosableFileFilter(defaultFilter);
//					 fc.addChoosableFileFilter(new
//					 DefaultFileFilter(".svg","SVG 文件 (.svg)"));
					fc.addChoosableFileFilter(new DefaultFileFilter(".html",
							"HTML 文件 (.html)"));

					fc.setFileFilter(xmlPngFilter);
					int rc = fc.showDialog(null, "保存");
					dialogShown = true;

					if (rc != JFileChooser.APPROVE_OPTION) {
						return;
					} else {
						lastDir = fc.getSelectedFile().getParent();
					}

					filename = fc.getSelectedFile().getAbsolutePath();
					selectedFilter = fc.getFileFilter();

					if (selectedFilter instanceof DefaultFileFilter) {
						String ext = ((DefaultFileFilter) selectedFilter)
								.getExtension();

						if (!filename.toLowerCase().endsWith(ext)) {
							filename += ext;
						}
					}

					if (new File(filename).exists()
							&& JOptionPane.showConfirmDialog(graphComponent,
									"要覆盖已有文件吗?") != JOptionPane.YES_OPTION) {
						return;
					}
				} else {
					filename = editor.getCurrentFile().getAbsolutePath();
				}

				try {
					String ext = filename
							.substring(filename.lastIndexOf('.') + 1);
//					 SVG暂时不支持
//					 if (ext.equalsIgnoreCase("svg"))
//					 {
//					 mxUtils.writeFile(mxUtils.getXml(mxCellRenderer
//					 .createSvgDocument(graph, null, 1, null, null)
//					 .getDocumentElement()), filename);
//					 }

					if (ext.equalsIgnoreCase("html")) {
						mxUtils.writeFile(mxUtils.getXml(mxCellRenderer
								.createHtmlDocument(graph, null, 1, null, null)
								.getDocumentElement()), filename);
					}
//					 else if (ext.equalsIgnoreCase("mxe")
//					 || ext.equalsIgnoreCase("xml"))
//					 {
//					 mxCodec codec = new mxCodec();
//					 String xml = mxUtils.getXml(codec.encode(graph
//					 .getModel()));
//					
//					 mxUtils.writeFile(xml, filename);
//					
//					 editor.setModified(false);
//					 editor.setCurrentFile(new File(filename));
//					 }
					else {
						Color bg = null;
						bg = graphComponent.getBackground();
//						 if ((!ext.equalsIgnoreCase("gif") &&
//						 !ext.equalsIgnoreCase("png"))||
//						 JOptionPane.showConfirmDialog(
//						 graphComponent, "需要透明背景吗?") !=
//						 JOptionPane.YES_OPTION)
//						 {
//						 bg = graphComponent.getBackground();
//						 }

						if (selectedFilter == xmlPngFilter
								|| (editor.getCurrentFile() != null
										&& ext.equalsIgnoreCase("png") && !dialogShown))

						{
							saveXmlPng(editor, filename, bg);
						} else {
							BufferedImage image = mxCellRenderer
									.createBufferedImage(graph, null, 1, bg,
											graphComponent.isAntiAlias(), null,
											graphComponent.getCanvas());

							if (image != null) {
								ImageIO.write(image, ext, new File(filename));
							} else {
								JOptionPane.showMessageDialog(graphComponent,
										"没有图像数据");
							}
						}
					}
				} catch (Exception ex) {
					JOptionPane.showMessageDialog(graphComponent,
							ex.toString(), "错误", JOptionPane.ERROR_MESSAGE);
				}
			}
		}
	}

	public static class SelectShortestPathAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected boolean directed;

		public SelectShortestPathAction(boolean directed) {
			this.directed = directed;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				mxGraph graph = graphComponent.getGraph();
				mxIGraphModel model = graph.getModel();

				Object source = null;
				Object target = null;

				Object[] cells = graph.getSelectionCells();

				for (int i = 0; i < cells.length; i++) {
					if (model.isVertex(cells[i])) {
						if (source == null) {
							source = cells[i];
						} else if (target == null) {
							target = cells[i];
						}
					}

					if (source != null && target != null) {
						break;
					}
				}

				if (source != null && target != null) {
					int steps = graph.getChildEdges(graph.getDefaultParent()).length;
					Object[] path = mxGraphAnalysis.getInstance()
							.getShortestPath(graph, source, target,
									new mxDistanceCostFunction(), steps,
									directed);
					graph.setSelectionCells(path);
				} else {
					JOptionPane.showMessageDialog(graphComponent,
							mxResources.get("noSourceAndTargetSelected"));
				}
			}
		}
	}

	public static class SelectSpanningTreeAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected boolean directed;

		public SelectSpanningTreeAction(boolean directed) {
			this.directed = directed;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				mxGraph graph = graphComponent.getGraph();
				mxIGraphModel model = graph.getModel();

				Object parent = graph.getDefaultParent();
				Object[] cells = graph.getSelectionCells();

				for (int i = 0; i < cells.length; i++) {
					if (model.getChildCount(cells[i]) > 0) {
						parent = cells[i];
						break;
					}
				}

				Object[] v = graph.getChildVertices(parent);
				Object[] mst = mxGraphAnalysis.getInstance()
						.getMinimumSpanningTree(graph, v,
								new mxDistanceCostFunction(), directed);
				graph.setSelectionCells(mst);
			}
		}

	}

	public static class ToggleDirtyAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				graphComponent.showDirtyRectangle = !graphComponent.showDirtyRectangle;
			}
		}
	}

	public static class ToggleConnectModeAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				mxConnectionHandler handler = graphComponent
						.getConnectionHandler();
				handler.setHandleEnabled(!handler.isHandleEnabled());
			}
		}
	}
	
	public static class ToggleCreateTargetItem extends JCheckBoxMenuItem {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public ToggleCreateTargetItem(final BasicNetworkEditor editor,
				String name) {
			super(name);
			setSelected(true);

			addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					mxGraphComponent graphComponent = editor
							.getGraphComponent();

					if (graphComponent != null) {
						mxConnectionHandler handler = graphComponent
								.getConnectionHandler();
						handler.setCreateTarget(!handler.isCreateTarget());
						setSelected(handler.isCreateTarget());
					}
				}
			});
		}
	}

	public static class PromptPropertyAction extends AbstractAction {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		protected Object target;

		protected String fieldname, message;

		public PromptPropertyAction(Object target, String message) {
			this(target, message, message);
		}

		public PromptPropertyAction(Object target, String message,
				String fieldname) {
			this.target = target;
			this.message = message;
			this.fieldname = fieldname;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof Component) {
				try {
					Method getter = target.getClass().getMethod(
							"get" + fieldname);
					Object current = getter.invoke(target);
					if (current instanceof Integer) {
						Method setter = target.getClass().getMethod(
								"set" + fieldname, new Class[] { int.class });

						String value = (String) JOptionPane.showInputDialog(
								(Component) e.getSource(), "Value", message,
								JOptionPane.PLAIN_MESSAGE, null, null, current);

						if (value != null) {
							setter.invoke(target, Integer.parseInt(value));
						}
					}
				} catch (Exception ex) {
					log.error(ex.getMessage());
				}
			}

			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				graphComponent.repaint();
			}
		}

	}

	public static class TogglePropertyItem extends JCheckBoxMenuItem {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public TogglePropertyItem(Object target, String name, String fieldname) {
			this(target, name, fieldname, false);
		}

		public TogglePropertyItem(Object target, String name, String fieldname,
				boolean refresh) {
			this(target, name, fieldname, refresh, null);
		}

		public TogglePropertyItem(final Object target, String name,
				final String fieldname, final boolean refresh,
				ActionListener listener) {
			super(name);
			if (listener != null) {
				addActionListener(listener);
			}

			addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					execute(target, fieldname, refresh);
				}
			});

			PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
				public void propertyChange(PropertyChangeEvent evt) {
					if (evt.getPropertyName().equalsIgnoreCase(fieldname)) {
						update(target, fieldname);
					}
				}

			};

			if (target instanceof mxGraphComponent) {
				((mxGraphComponent) target)
						.addPropertyChangeListener(propertyChangeListener);
			} else if (target instanceof mxGraph) {
				((mxGraph) target)
						.addPropertyChangeListener(propertyChangeListener);
			}

			update(target, fieldname);
		}

		public void update(Object target, String fieldname) {
			if (target != null && fieldname != null) {
				try {
					Method getter = target.getClass().getMethod(
							"is" + fieldname);

					if (getter != null) {
						Object current = getter.invoke(target);

						if (current instanceof Boolean) {
							setSelected(((Boolean) current).booleanValue());
						}
					}
				} catch (Exception e) {
					log.error(e.getMessage());
				}
			}
		}

		public void execute(Object target, String fieldname, boolean refresh) {
			if (target != null && fieldname != null) {
				try {
					Method getter = target.getClass().getMethod(
							"is" + fieldname);
					Method setter = target.getClass().getMethod(
							"set" + fieldname, new Class[] { boolean.class });

					Object current = getter.invoke(target);

					if (current instanceof Boolean) {
						boolean value = !((Boolean) current).booleanValue();
						setter.invoke(target, value);
						setSelected(value);
					}

					if (refresh) {
						mxGraph graph = null;

						if (target instanceof mxGraph) {
							graph = (mxGraph) target;
						} else if (target instanceof mxGraphComponent) {
							graph = ((mxGraphComponent) target).getGraph();
						}

						graph.refresh();
					}
				} catch (Exception e) {
					log.error(e.getMessage());
				}
			}
		}

	}

	/**
	 * 设置图元的字体，true为粗体,false是斜体
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class FontStyleAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected boolean bold;

		public FontStyleAction(boolean bold) {
			this.bold = bold;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				Component editorComponent = null;

				if (graphComponent.getCellEditor() instanceof mxCellEditor) {
					editorComponent = ((mxCellEditor) graphComponent
							.getCellEditor()).getEditor();
				}

				if (editorComponent instanceof JEditorPane) {
					JEditorPane editorPane = (JEditorPane) editorComponent;
					int start = editorPane.getSelectionStart();
					int ende = editorPane.getSelectionEnd();
					String text = editorPane.getSelectedText();

					if (text == null) {
						text = "";
					}

					try {
						HTMLEditorKit editorKit = new HTMLEditorKit();
						HTMLDocument document = (HTMLDocument) editorPane
								.getDocument();
						document.remove(start, (ende - start));
						editorKit.insertHTML(document, start, ((bold) ? "<b>"
								: "<i>") + text + ((bold) ? "</b>" : "</i>"),
								0, 0, (bold) ? HTML.Tag.B : HTML.Tag.I);
					} catch (Exception ex) {
						ex.printStackTrace();
					}

					editorPane.requestFocus();
					editorPane.select(start, ende);
				} else {
					mxIGraphModel model = graphComponent.getGraph().getModel();
					model.beginUpdate();
					try {
						graphComponent.stopEditing(false);
						graphComponent.getGraph().toggleCellStyleFlags(
								mxConstants.STYLE_FONTSTYLE,
								(bold) ? mxConstants.FONT_BOLD
										: mxConstants.FONT_ITALIC);
					} finally {
						model.endUpdate();
					}
				}
			}
		}
	}

	/**
	 * 设置mxCell的警告
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class WarningAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				Object[] cells = graphComponent.getGraph().getSelectionCells();

				if (cells != null && cells.length > 0) {
					String warning = JOptionPane.showInputDialog(mxResources
							.get("enterWarningMessage"));
					for (int i = 0; i < cells.length; i++) {
						// 设置某个元素警告通知
						graphComponent.setCellWarning(cells[i], warning);
					}
				} else {
					JOptionPane.showMessageDialog(graphComponent,
							mxResources.get("noCellSelected"));
				}
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ToggleAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected String key;
		protected boolean defaultValue;

		/**
		 * 虚连接线
		 * @param key
		 */
		public ToggleAction(String key) {
			this(key, false);
		}
		
		public ToggleAction(String key, boolean defaultValue) {
			this.key = key;
			this.defaultValue = defaultValue;
		}
		
		public void actionPerformed(ActionEvent e) {
			mxGraph graph = mxGraphActions.getGraph(e);

			if (graph != null) {
				graph.toggleCellStyles(key, defaultValue);
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class SetLabelPositionAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected String labelPosition;
		protected String alignment;
		
		public SetLabelPositionAction(String labelPosition, String alignment) {
			this.labelPosition = labelPosition;
			this.alignment = alignment;
		}
		
		public void actionPerformed(ActionEvent e) {
			mxGraph graph = mxGraphActions.getGraph(e);

			if (graph != null && !graph.isSelectionEmpty()) {
				graph.getModel().beginUpdate();
				try {
					// Checks the orientation of the alignment to use the
					// correct constants
					if (labelPosition.equals(mxConstants.ALIGN_LEFT)
							|| labelPosition.equals(mxConstants.ALIGN_CENTER)
							|| labelPosition.equals(mxConstants.ALIGN_RIGHT)) {
						graph.setCellStyles(mxConstants.STYLE_LABEL_POSITION,
								labelPosition);
						graph.setCellStyles(mxConstants.STYLE_ALIGN, alignment);
					} else {
						graph.setCellStyles(
								mxConstants.STYLE_VERTICAL_LABEL_POSITION,
								labelPosition);
						graph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN,
								alignment);
					}
				} finally {
					graph.getModel().endUpdate();
				}
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class SetStyleAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected String value;

		public SetStyleAction(String value) {
			this.value = value;
		}
		
		public void actionPerformed(ActionEvent e) {
			mxGraph graph = mxGraphActions.getGraph(e);

			if (graph != null && !graph.isSelectionEmpty()) {
				graph.setCellStyle(value);
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class KeyValueAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected String key, value;
		
		public KeyValueAction(String key) {
			this(key, null);
		}
		
		public KeyValueAction(String key, String value) {
			this.key = key;
			this.value = value;
		}
		
		public void actionPerformed(ActionEvent e) {
			mxGraph graph = mxGraphActions.getGraph(e);

			if (graph != null && !graph.isSelectionEmpty()) {
				graph.setCellStyles(key, value);
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class PromptValueAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		protected String key, message;

		public PromptValueAction(String key, String message) {
			this.key = key;
			this.message = message;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof Component) {
				mxGraph graph = mxGraphActions.getGraph(e);

				if (graph != null && !graph.isSelectionEmpty()) {
					String value = (String) JOptionPane.showInputDialog(
							(Component) e.getSource(),
							mxResources.get("value"), message,
							JOptionPane.PLAIN_MESSAGE, null, null, "");

					if (value != null) {
						if (value.equals(mxConstants.NONE)) {
							value = null;
						}

						graph.setCellStyles(key, value);
					}
				}
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class AlignCellsAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		protected String align;
		
		public AlignCellsAction(String align) {
			this.align = align;
		}

		public void actionPerformed(ActionEvent e) {
			mxGraph graph = mxGraphActions.getGraph(e);

			if (graph != null && !graph.isSelectionEmpty()) {
				graph.alignCells(align);
			}
		}
	}

	/**
	 * 
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class AutosizeAction extends AbstractAction {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * 
		 */
		public void actionPerformed(ActionEvent e) {
			mxGraph graph = mxGraphActions.getGraph(e);

			if (graph != null && !graph.isSelectionEmpty()) {
				Object[] cells = graph.getSelectionCells();
				mxIGraphModel model = graph.getModel();

				model.beginUpdate();
				try {
					for (int i = 0; i < cells.length; i++) {
						graph.updateCellSize(cells[i]);
					}
				} finally {
					model.endUpdate();
				}
			}
		}
	}

	/**
	 * 颜色，key是要设置的属性名称
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class ColorAction extends AbstractAction {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		protected String name, key;

		public ColorAction(String name, String key) {
			this.name = name;
			this.key = key;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				mxGraph graph = graphComponent.getGraph();

				if (!graph.isSelectionEmpty()) {
					Color newColor = JColorChooser.showDialog(graphComponent,
							name, null);

					if (newColor != null) {
						graph.setCellStyles(key, mxUtils.hexString(newColor));
					}
				}
			}
		}
	}

	/**
	 * 设置画布的背景图片
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class BackgroundImageAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				String value = (String) JOptionPane.showInputDialog(
						graphComponent, mxResources.get("backgroundImage"),
						"URL", JOptionPane.PLAIN_MESSAGE, null, null,
						"http://www.callatecs.com/images/background2.JPG");

				if (value != null) {
					if (value.length() == 0) {
						graphComponent.setBackgroundImage(null);
					} else {
						Image background = mxUtils.loadImage(value);
						// Incorrect URLs will result in no image.
						// TODO provide feedback that the URL is not correct
						if (background != null) {
							graphComponent.setBackgroundImage(new ImageIcon(
									background));
						}
					}

					// Forces a repaint of the outline
					graphComponent.getGraph().repaint();
				}
			}
		}
	}

	/**
	 * 设置画布的背景颜色
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class BackgroundAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				Color newColor = JColorChooser.showDialog(graphComponent,
						mxResources.get("background"), null);

				if (newColor != null) {
					graphComponent.getViewport().setOpaque(false);
					graphComponent.setBackground(newColor);
				}
				graphComponent.getGraph().repaint();
			}
		}
	}

	/**
	 * 画布是Page状态的时候，page的背景颜色
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class PageBackgroundAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				Color newColor = JColorChooser.showDialog(graphComponent,
						mxResources.get("pageBackground"), null);

				if (newColor != null) {
					graphComponent.setPageBackgroundColor(newColor);
				}
				graphComponent.repaint();
			}
		}
	}

	/**
	 * 样式
	 * @author zhangzuoqiang
	 * <br/>Date: Aug 25, 2011
	 */
	public static class StyleAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() instanceof mxGraphComponent) {
				mxGraphComponent graphComponent = (mxGraphComponent) e
						.getSource();
				mxGraph graph = graphComponent.getGraph();
				String initial = graph.getModel().getStyle(
						graph.getSelectionCell());
				String value = (String) JOptionPane.showInputDialog(
						graphComponent, mxResources.get("style"),
						mxResources.get("style"), JOptionPane.PLAIN_MESSAGE,
						null, null, initial);

				if (value != null) {
					graph.setCellStyle(value);
				}
			}
		}
	}
	
	public static class WelcomeAction extends AbstractAction {		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			System.out.println("Welcome ... ");
		}
	}
}